// MGCommandPage.cpp: implementation of the CMGCommandPage class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ResourceInstance.h"
#include "MGCommandPage.h"
#include "MGCfg.h"
#include "AdvanceCommand.h"
#include "MsHtmHst.h"

const unsigned int CMGCommandPage::MAX_GESTURE_INPUT = 256;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMGCommandPage::CMGCommandPage() : m_bWheelCommand(FALSE), m_bMiddleButton(FALSE), m_nGestureSelected(LB_ERR), m_bInitDialog(FALSE)
{
	m_psp.hInstance = CResourceInstance::Get();

	EnableHelp();
}

CMGCommandPage::~CMGCommandPage()
{
	std::for_each( m_vlpCommand.begin(), m_vlpCommand.end(), COMMANDVECTOR::Delete_t() );
}

#include "tutils.h"

BOOL CMGCommandPage::OnInitDialog(HWND hwndFocus, LPARAM lParam)
{
	c_cbCategory.Attach(GetDlgItem(IDC_CB_CATEGORY));
	c_cbTarget.Attach(GetDlgItem(IDC_CB_TARGET));
	c_lbCommand.Attach(GetDlgItem(IDC_LB_COMMAND));

	c_pbWheelUp.Attach(GetDlgItem(IDC_PB_WHEEL_UP));
	c_pbWheelDown.Attach(GetDlgItem(IDC_PB_WHEEL_DOWN));
	c_pbUp.Attach(GetDlgItem(IDC_PB_UP));
	c_pbDown.Attach(GetDlgItem(IDC_PB_DOWN));
	c_pbRight.Attach(GetDlgItem(IDC_PB_RIGHT));
	c_pbLeft.Attach(GetDlgItem(IDC_PB_LEFT));
	c_pbBackspace.Attach(GetDlgItem(IDC_PB_BACKSPACE));

	c_pbRightButton.Attach(GetDlgItem(IDC_PB_RIGHT_BUTTON));
	c_pbLeftButton.Attach(GetDlgItem(IDC_PB_LEFT_BUTTON));
	c_pbMiddleButton.Attach(GetDlgItem(IDC_PB_MIDDLE_BUTTON));

	c_pbAdd.Attach(GetDlgItem(IDC_PB_ADD));
	c_pbRemove.Attach(GetDlgItem(IDC_PB_REMOVE));

	c_edGestureInput.Attach(GetDlgItem(IDC_ED_GESTURE_INPUT));

	c_pbLoadGestures.Attach(GetDlgItem(IDC_PB_LOAD_GESTURES));
	c_pbSaveGestures.Attach(GetDlgItem(IDC_PB_SAVE_GESTURES));

	c_lcRegisteredMouseGesture.Attach(GetDlgItem(IDC_LC_REGISTERED_MOUSE_GESTURES));

	enum { BUF_SIZE = 100 };
	TCHAR sBuf[BUF_SIZE];
	::ZeroMemory( sBuf, BUF_SIZE * sizeof(TCHAR) );

	::LoadString(CResourceInstance::Get(), IDS_GESTURE, sBuf, BUF_SIZE);
	c_lcRegisteredMouseGesture.InsertColumn(0, sBuf, LVCFMT_LEFT, 200, 0);
	::LoadString(CResourceInstance::Get(), IDS_COMMAND, sBuf, BUF_SIZE);
	c_lcRegisteredMouseGesture.InsertColumn(1, sBuf, LVCFMT_LEFT, 150, 0);
	::LoadString(CResourceInstance::Get(), IDS_TARGET, sBuf, BUF_SIZE);
	c_lcRegisteredMouseGesture.InsertColumn(2, sBuf, LVCFMT_LEFT, 100, 0);
	ListView_SetExtendedListViewStyle(c_lcRegisteredMouseGesture.m_hWnd, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);

	InitCommands();

	UpdateRegistredGestureList();
	UpdateControls();

	
	return (m_bInitDialog = TRUE);
}

void CMGCommandPage::OnEnChangeEdGestureInput(UINT uCode, int nID, HWND hwndCtrl)
{
	if(m_bInitDialog)
	{
		enum { BUF_SIZE = MAX_GESTURE_INPUT };
		TCHAR sGesture[BUF_SIZE];
		::ZeroMemory( sGesture, BUF_SIZE * sizeof(TCHAR) );

		c_edGestureInput.GetWindowText(sGesture, BUF_SIZE);

		int nFound = MGCfg::Get().List().Find(sGesture);

		if(0 <= nFound)
		{
			//	c_lcRegisteredMouseGesture.SetFocus();
			c_lcRegisteredMouseGesture.SetItemState(nFound, LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
			c_lcRegisteredMouseGesture.EnsureVisible(nFound, FALSE);
		}
		else
		{
			c_lcRegisteredMouseGesture.SetItemState(m_nGestureSelected, !LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
			m_nGestureSelected = -1;
		}
	}
}

void CMGCommandPage::OnBnClickedPbLoadGestures(UINT uCode, int nID, HWND hwndCtrl)
{
	// TODO: Add your control notification handler code here
	static const TCHAR szFilter[] = _T("Mouse Gesture File (*.ini)\0*.ini\0All Files (*.*)\0*.*\0\0");
	CFileDialog dlgFile(TRUE, _T("ini"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);
		
	if(dlgFile.DoModal() == IDCANCEL) return; 
		
	MGCfg::Get().List().Load(dlgFile.m_szFileName);
		
	UpdateRegistredGestureList();
}

void CMGCommandPage::OnBnClickedPbSaveGestures(UINT uCode, int nID, HWND hwndCtrl)
{
	static const TCHAR szFilter[] = _T("Mouse Gesture File (*.ini)\0*.ini\0All Files (*.*)\0*.*\0\0");
	CFileDialog dlgFile(FALSE, _T("ini"), _T("Gesture.ini"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

	if(dlgFile.DoModal() == IDCANCEL) return;

	MGCfg::Get().List().Save(dlgFile.m_szFileName);
}

void CMGCommandPage::OnBnClickedPbAdd(UINT uCode, int nID, HWND hwndCtrl)
{
	enum { BUF_SIZE = MAX_GESTURE_INPUT };
	TCHAR sGesturePattern[BUF_SIZE];
	::ZeroMemory( sGesturePattern, BUF_SIZE * sizeof(TCHAR) );

	c_edGestureInput.GetWindowText(sGesturePattern, BUF_SIZE);
	c_edGestureInput.SetWindowText( _T("") );

	m_bWheelCommand = FALSE;
	
	LPCOMMAND pCommand = m_vlpCommand.at( c_lbCommand.GetItemData( c_lbCommand.GetCurSel() ) );

	BYTE bTargetSelected = (BYTE)c_cbTarget.GetItemData( c_cbTarget.GetCurSel() );

	GESTURE tempGesture( sGesturePattern,
		pCommand->wID,
		pCommand->pszID,
		_T(""),
		pCommand->bCatID | bTargetSelected );

	MGCfg::Get().List().Add(&tempGesture);
	
	UpdateRegistredGestureList();
	UpdateControls();
}

void CMGCommandPage::OnBnClickedPbRemove(UINT uCode, int nID, HWND hwndCtrl)
{
	c_lcRegisteredMouseGesture.DeleteItem(m_nGestureSelected);
	MGCfg::Get().List().Remove(m_nGestureSelected);

	UpdateRegistredGestureList();

	int nItemCount = c_lcRegisteredMouseGesture.GetItemCount();
	m_nGestureSelected = m_nGestureSelected ==  nItemCount ? nItemCount - 1 : m_nGestureSelected;
	c_lcRegisteredMouseGesture.SetFocus();
	c_lcRegisteredMouseGesture.SetItemState(m_nGestureSelected, LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
	//	c_lcRegisteredMouseGesture.EnsureVisible(m_nGestureSelected, FALSE);

	UpdateControls();
}

void CMGCommandPage::OnBnClickedMouse(UINT uCode, int nID, HWND hwndCtrl)
{
	enum { BUF_SIZE = 256 };
	TCHAR sGesture[BUF_SIZE];
	::ZeroMemory( sGesture, BUF_SIZE * sizeof(TCHAR) );

	if(m_bWheelCommand)
	{
		m_bWheelCommand = FALSE;
	}
	else
	{
		c_edGestureInput.GetWindowText(sGesture, BUF_SIZE);
	}

	TCHAR sMark[3] = _T("  ");
	switch(nID)
	{
	case IDC_PB_UP:
		sMark[0] = MGCfg::Get().List().GetArrowMark(MG::ARROW_UP);
		break;

	case IDC_PB_DOWN:
		sMark[0] = MGCfg::Get().List().GetArrowMark(MG::ARROW_DOWN);
		break;

	case IDC_PB_LEFT:
		sMark[0] = MGCfg::Get().List().GetArrowMark(MG::ARROW_LEFT);
		break;

	case IDC_PB_RIGHT:
		sMark[0] = MGCfg::Get().List().GetArrowMark(MG::ARROW_RIGHT);
		break;

	case IDC_PB_LEFT_BUTTON:
		sMark[0] = MGCfg::Get().List().GetKeyMark(MG::KEY_BUTTON1);
		break;

	case IDC_PB_MIDDLE_BUTTON:
		sMark[0] = MGCfg::Get().List().GetKeyMark(MG::KEY_BUTTON2);
		break;

	case IDC_PB_RIGHT_BUTTON:
		sMark[0] = MGCfg::Get().List().GetKeyMark(MG::KEY_BUTTON2);
		break;
	}

	if( BUF_SIZE - 2 > ::_tcslen(sGesture) )
		::_tcscat(sGesture, sMark);

	c_edGestureInput.SetWindowText(sGesture);

	UpdateControls();
}

void CMGCommandPage::OnBnClickedWheel(UINT uCode, int nID, HWND hwndCtrl)
{
	m_bWheelCommand = TRUE;

	TCHAR sMark[3] = _T("  ");
	switch(nID)
	{
	case IDC_PB_WHEEL_UP:
		sMark[0] = MGCfg::Get().List().GetKeyMark(MG::KEY_WHEEL_UP);
		break;

	case IDC_PB_WHEEL_DOWN:
		sMark[0] = MGCfg::Get().List().GetKeyMark(MG::KEY_WHEEL_DOWN);
		break;
	}

	c_edGestureInput.SetWindowText(sMark);

	UpdateControls();
}

void CMGCommandPage::OnBnClickedPbBackspace(UINT uCode, int nID, HWND hwndCtrl)
{
	if(m_bWheelCommand)
	{
		m_bWheelCommand = FALSE;

		c_edGestureInput.SetWindowText(_T(""));
	}
	else
	{
		enum { BUF_SIZE = MAX_GESTURE_INPUT };
		TCHAR sGesture[BUF_SIZE];
		::ZeroMemory( sGesture, BUF_SIZE * sizeof(TCHAR) );

		c_edGestureInput.GetWindowText(sGesture, BUF_SIZE);

		LPTSTR sCurrent = sGesture;
		while( *(::CharNext(::CharNext( sCurrent ) ) ) )
		{
			sCurrent = ::CharNext(sCurrent);
		}
		*sCurrent = NULL;

		c_edGestureInput.SetWindowText(sGesture);
	}

	UpdateControls();
}

void CMGCommandPage::OnSelChangeLbCommand(UINT uCode, int nID, HWND hwndCtrl)
{
	int nCurSel = c_lbCommand.GetCurSel();
	if (LB_ERR != nCurSel)
	{
		LPCOMMAND pCommand = m_vlpCommand.at( (int)c_lbCommand.GetItemData(nCurSel) );
		if( _tcsstr( pCommand->pszID, _T("...") )
			|| (ADVANCE::CAT_CONTEXT_MENU_BASE <= pCommand->bCatID && ADVANCE::TARGET_ALL > pCommand->bCatID)  )
		{
			if(0 != c_cbTarget.GetCurSel())
			{
				::MessageBeep(-1);
				c_cbTarget.SetCurSel(0);
			}
		}
	}

	UpdateControls();
}

void CMGCommandPage::OnSelChangeCbCategory(UINT uCode, int nID, HWND hwndCtrl)
{
	int nCurSel = c_cbCategory.GetCurSel();
	if (CB_ERR != nCurSel)
	{
		ReloadCommand( (BYTE)c_cbCategory.GetItemData(nCurSel) );
	}

	UpdateControls();
}

void CMGCommandPage::OnSelChangeCbTarget(UINT uCode, int nID, HWND hwndCtrl)
{
	int nCurSel = c_cbTarget.GetCurSel();
	if (CB_ERR != nCurSel)
	{
		int nCurSelCommand = c_lbCommand.GetCurSel();
		if(CB_ERR != nCurSelCommand)
		{
			LPCOMMAND pCommand = m_vlpCommand.at( c_lbCommand.GetItemData( nCurSelCommand ) );
			if( _tcsstr( pCommand->pszID, _T("...") )
				|| (ADVANCE::CAT_CONTEXT_MENU_BASE <= pCommand->bCatID && ADVANCE::TARGET_ALL > pCommand->bCatID) )
			{
				if(0 != c_cbTarget.GetCurSel())
				{
					::MessageBeep(-1);
					c_cbTarget.SetCurSel(0);
				}
			}
		}
	}

	UpdateControls();
}

// CMGOptionPage::UpdateControl()
// QuerySiblings(IDD_MG_OPTION, MAKELPARAM( bUseMouseGesture, ( 1 == c_rbRightButton.GetCheck() ) ) );
LRESULT CMGCommandPage::OnQuerySiblings(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if(IDD_MG_OPTION == wParam)
	{
		m_bMiddleButton = (BOOL)HIWORD(lParam);

		UpdateControls();

		return IDD_MG_COMMAND;
	}

	return 0;
}

LRESULT CMGCommandPage::OnItemChangedLcRegisteredMouseGestures(LPNMHDR pNMHDR)
{
	NM_LISTVIEW *pNMListView = reinterpret_cast<NM_LISTVIEW *>(pNMHDR);

	if(LVIS_SELECTED & pNMListView->uNewState)
	{
		m_nGestureSelected = pNMListView->iItem;
	}
	
	UpdateControls();

	return 0;
}

LRESULT CMGCommandPage::OnKillFocusLcRegisteredMouseGestures(LPNMHDR pNMHDR)
{
	//	c_lcRegisteredMouseGesture.SetItemState(m_nGestureSelected, !LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);

	UpdateControls();

	return 0;
}

LRESULT CMGCommandPage::OnGetInfoTipLcRegisteredMouseGestures(LPNMHDR pNMHDR)
{
	NMLVGETINFOTIP *pInfoTip = reinterpret_cast<NMLVGETINFOTIP *>(pNMHDR);
	if (pInfoTip)
	{
		LPGESTURE pGesture = MGCfg::Get().List().Get(pInfoTip->iItem);
		if (pGesture)
		{
			std::tostringstream tss;
			tss << _T("\"") << pGesture->pattern.GetAsString().c_str() << _T("\" ")
				<< pGesture->pszID << _T(" (") << pGesture->wID << _T(")");

			::_tcsncpy(pInfoTip->pszText, tss.str().c_str(), pInfoTip->cchTextMax);
		}
	}

	return 0;
}

void CMGCommandPage::UpdateControls()
{
	// update controls state
	int nCurSel = c_lbCommand.GetCurSel();
	c_pbAdd.EnableWindow(LB_ERR != nCurSel);
	
	c_pbMiddleButton.EnableWindow(!m_bMiddleButton);
	c_pbRightButton.EnableWindow(m_bMiddleButton);
	
	BSTR sWindowText = ::SysAllocString(NULL);
	c_edGestureInput.GetWindowText(sWindowText);
	c_pbAdd.EnableWindow(LB_ERR != c_lbCommand.GetCurSel() && 0 != ::SysStringLen(sWindowText) );
	::SysFreeString(sWindowText);
	c_pbRemove.EnableWindow(LB_ERR != m_nGestureSelected);
}

void CMGCommandPage::UpdateRegistredGestureList()
{
	if ( ::IsWindow(c_lcRegisteredMouseGesture.m_hWnd) )
	{
		c_lcRegisteredMouseGesture.DeleteAllItems();

		int nGesture = MGCfg::Get().List().GetCount();
		c_lcRegisteredMouseGesture.SetItemCount(nGesture);
		for (int i = 0; i < nGesture; i++)
		{
			LPGESTURE pGesture = MGCfg::Get().List().Get(i);

			c_lcRegisteredMouseGesture.InsertItem(i, pGesture->pattern.GetAsString().c_str());
			c_lcRegisteredMouseGesture.SetItemText(i, 1, pGesture->pszID);
			
			enum { BUF_SIZE = 100 };
			TCHAR sBuf[BUF_SIZE];
			::ZeroMemory(sBuf, BUF_SIZE * sizeof(TCHAR));

			if(ADVANCE::TARGET_ALL & pGesture->bCatID)
			{
				::LoadString(CResourceInstance::Get(), IDS_TARGET_ALL, sBuf, BUF_SIZE);
				c_lcRegisteredMouseGesture.SetItemText(i, 2, sBuf);
			}
			else
			{
				::LoadString(CResourceInstance::Get(), IDS_TARGET_ACTIVE, sBuf, BUF_SIZE);
				c_lcRegisteredMouseGesture.SetItemText(i, 2, sBuf );
			}
		}
	}
}

const CBDATA CMGCommandPage::rgCategory[] =
{
	{ IDS_CAT_ADVANCE,	ADVANCE::CAT_ADVANCE },
	{ IDS_CAT_ALL,		ADVANCE::CAT_ALL },
};

void CMGCommandPage::InitCommands()
{
	// intialze menu and categories
	EnumIEMenu();

	EnumIEContextMenu();

	enum { BUF_SIZE = 100 };
	TCHAR sBuf[BUF_SIZE];
	::ZeroMemory(sBuf, BUF_SIZE * sizeof(TCHAR));

	::LoadString(CResourceInstance::Get(), rgCategory[0].uID, sBuf, BUF_SIZE);
	AddCategory((BYTE)rgCategory[0].dwValue, sBuf);
	AddAdvanceMenu();

	::LoadString(CResourceInstance::Get(), rgCategory[1].uID, sBuf, BUF_SIZE);
	AddCategory((BYTE)rgCategory[1].dwValue, sBuf);
	c_cbCategory.SetCurSel(c_cbCategory.GetCount() - 1);

	ReloadCommand(ADVANCE::CAT_ALL);

	// intialize target
	InitTargets();
}

void CMGCommandPage::EnumIEMenu()
{
	TCHAR szLibraryPath[MAX_PATH];
	LPTSTR pszFilePart = NULL;
	DWORD dwLen = ::SearchPath(
		NULL,						// search path
		_T("BrowseLC.dll"),			// file name
		NULL,						// file extension
		MAX_PATH,					// size of buffer
		szLibraryPath,				// found file name buffer
		&pszFilePart				// file component
		);
	
	if(0 < dwLen)
	{
		HMODULE hBrowse = ::LoadLibrary(szLibraryPath);
		if(hBrowse)
		{
			HMENU hMenu = ::LoadMenu( hBrowse, MAKEINTRESOURCE(267) );

			int nDepth = 0;
			DFSMenu(hMenu, nDepth);
			
			::DestroyMenu(hMenu);
			
			::FreeLibrary(hBrowse);
		}
	}
}

void CMGCommandPage::DFSMenu(HMENU hMenu, int &rnDepth, LPCTSTR pszPrefix/* = NULL*/, BYTE bCatID/* = -1*/)
{
	if(NULL == hMenu) return;

	rnDepth++;

	enum { BUF_SIZE = 100 };
	TCHAR buf[BUF_SIZE];

	int nCount = ::GetMenuItemCount(hMenu);
	for(int i = 0; i < nCount; i++)
	{
		std::tstring strMenuItem;
		std::tstring strPrefix(pszPrefix ? pszPrefix : _T(""));

		UINT nState = ::GetMenuState(hMenu, i, MF_BYPOSITION);
		if( (MF_POPUP & nState) || !(MF_SEPARATOR & nState) )
		{
			int nID = ::GetMenuItemID(hMenu, i);
			::GetMenuString(hMenu, i, buf, BUF_SIZE, MF_BYPOSITION);
			strMenuItem = (LPCTSTR)buf;

			/// remove accelator string part
			UINT iPos = strMenuItem.find(_T('\t'));
			if(iPos != std::tstring::npos)
				strMenuItem.erase(iPos);
			
			/// remove all single &
			iPos = strMenuItem.find(_T('&'));
			while(iPos != std::tstring::npos)
			{
				strMenuItem.erase(iPos, 1);
				
				iPos = strMenuItem.find(_T('&') , (_T('&') == strMenuItem[iPos]) ? iPos + 1 : iPos);
			}

			if(1 == rnDepth && -1 == nID)
			{
				/// add category
				bCatID = ADVANCE::CAT_MENU_BASE + i;
				AddCategory(bCatID, strMenuItem.c_str());
			}
			
			if(-1 != nID && 41342 != nID)
			{
				// nID = 41342 : Favorites/(Empty) menu
				/// add menu item
				std::tostringstream tss;
				tss << strPrefix.c_str() << (LPCTSTR)strMenuItem.c_str();
				AddCommand(nID, tss.str().c_str(), bCatID);
			}
		}

		if(1 < rnDepth)
		{
			strPrefix += strMenuItem;
			if(!strMenuItem.empty()) strPrefix += _T(" ");
		}
		
		// DFS(depth-first search) : trasverse menu item recursively
		DFSMenu( ::GetSubMenu(hMenu, i), rnDepth, strPrefix.c_str(), bCatID );
	}

	rnDepth--;
}

void CMGCommandPage::EnumIEContextMenu()
{
	enum
	{
		IDR_BROWSE_CONTEXT_MENU = 24641,
	};
	
	TCHAR szLibraryPath[MAX_PATH];
	LPTSTR pszFilePart = NULL;
	DWORD dwLen = ::SearchPath(
		NULL,						// search path
		_T("SHDOCLC.dll"),			// file name
		NULL,						// file extension
		MAX_PATH,					// size of buffer
		szLibraryPath,				// found file name buffer
		&pszFilePart				// file component
		);
	
	if(0 < dwLen)
	{
		HMODULE hBrowse = ::LoadLibrary(szLibraryPath);

		if(hBrowse)
		{
			HMENU hMenu = ::LoadMenu( hBrowse, MAKEINTRESOURCE(IDR_BROWSE_CONTEXT_MENU) );
	
			// default context menu
			AddContextMenu(hMenu, CONTEXT_MENU_DEFAULT);

			// context menu for image element
			AddContextMenu(hMenu, CONTEXT_MENU_IMAGE);

			// context menu for anchor element
			AddContextMenu(hMenu, CONTEXT_MENU_ANCHOR);
		
			::DestroyMenu(hMenu);

			::FreeLibrary(hBrowse);
		}
	}
}

void CMGCommandPage::AddContextMenu(HMENU hMenu, DWORD dwID)
{
	enum { BUF_SIZE = 100 };
	TCHAR sBuf[BUF_SIZE];
	::ZeroMemory(sBuf, BUF_SIZE * sizeof(TCHAR));

	::LoadString(CResourceInstance::Get(), IDS_CONTEXT_MENU, sBuf, BUF_SIZE);
	std::tstring sMenu ( sBuf );

	::GetMenuString(hMenu, dwID, sBuf, BUF_SIZE, MF_BYPOSITION);
	sMenu += _T(" | ");
	sMenu += sBuf;

	AddCategory(ADVANCE::CAT_CONTEXT_MENU_BASE + (BYTE)dwID, sMenu.c_str());
	
	std::tostringstream tss;

	HMENU hContextMenu = ::GetSubMenu(hMenu, dwID);
	int nCount = ::GetMenuItemCount(hContextMenu);
	for(int i = 0; i < nCount; i++)
	{
		std::tstring strMenuItem;
		
		UINT nState = ::GetMenuState(hContextMenu, i, MF_BYPOSITION);
		if( (MF_POPUP & nState) || !(MF_SEPARATOR & nState) )
		{
			int nID = ::GetMenuItemID(hContextMenu, i);
			::GetMenuString(hContextMenu, i, sBuf, BUF_SIZE, MF_BYPOSITION);
			strMenuItem = sBuf;
			
			/// remove accelator string part
			UINT iPos = strMenuItem.find(_T('\t'));
			if(iPos != std::tstring::npos)
				strMenuItem.erase(iPos);
			
			/// remove all single &
			iPos = strMenuItem.find(_T('&'));
			while(iPos != std::tstring::npos)
			{
				strMenuItem.erase(iPos, 1);
				
				iPos = strMenuItem.find(_T('&') , (_T('&') == strMenuItem[iPos]) ? iPos + 1 : iPos);
			}
			
			if(-1 != nID && 2292 != nID)
			{
				// nID = 2292 : CONTEXT_MENU_DEFAULT/Encoding
				/// add menu item
				std::tostringstream tss;
				tss << strMenuItem.c_str() << _T(" | ") << sMenu.c_str();
				AddCommand(nID, tss.str().c_str(), ADVANCE::CAT_CONTEXT_MENU_BASE + (BYTE)dwID);
			}
		}
	}
}

void CMGCommandPage::AddCommand(WORD wID, LPCTSTR pszID, BYTE bCatID)
{
	LPCOMMAND pCommand = new COMMAND;
	pCommand->wID = wID;

	int nLen = ::lstrlen(pszID);
	pCommand->pszID = new TCHAR[nLen + 1];
	::lstrcpyn(pCommand->pszID, pszID, nLen + 1);

	pCommand->bCatID = bCatID;

	m_vlpCommand.push_back(pCommand);
}

void CMGCommandPage::AddCategory(BYTE bCatID, LPCTSTR pszCat)
{
	int nCategory = c_cbCategory.GetCount();
	c_cbCategory.InsertString(nCategory, pszCat);
	c_cbCategory.SetItemData(nCategory, (DWORD)bCatID);
}

const CBDATA CMGCommandPage::rgTarget[] =
{
	{ IDS_TARGET_ACTIVE,	ADVANCE::TARGET_ACTIVE },
	{ IDS_TARGET_ALL,		ADVANCE::TARGET_ALL },
};

void CMGCommandPage::InitTargets()
{
	c_cbTarget.ResetContent();

	enum { BUF_SIZE = 100 };
	TCHAR sBuf[BUF_SIZE];
	::ZeroMemory(sBuf, BUF_SIZE * sizeof(TCHAR));

	for(int i = 0; i < sizeof(rgTarget) / sizeof(rgTarget[0]); i++)
	{
		::LoadString(CResourceInstance::Get(), rgTarget[i].uID, sBuf, BUF_SIZE);
		c_cbTarget.InsertString( i, sBuf );
		c_cbTarget.SetItemData( i, rgTarget[i].dwValue );
	}

	c_cbTarget.SetCurSel(0);
}

int CMGCommandPage::ReloadCommand(BYTE bCatID)
{
	c_lbCommand.ResetContent();

	int iCommand = 0;
	std::vector<int> viCommand;
	std::vector<LPCOMMAND>::iterator it = m_vlpCommand.begin(), itEnd = m_vlpCommand.end();
	while(it != itEnd)
	{
		if(ADVANCE::CAT_ALL == bCatID || bCatID == (*it)->bCatID)
		{
			viCommand.push_back(iCommand);
		}

		it++, iCommand++;
	}

	std::vector<int>::iterator itIndex = viCommand.begin(), itIndexEnd = viCommand.end();
	std::sort( itIndex, itIndexEnd, CMGCommandPage::COMMANDCOMP(m_vlpCommand) );

	int iLbIndex = 0;
	while(itIndex != itIndexEnd)
	{
		c_lbCommand.InsertString(iLbIndex, m_vlpCommand.at( (*itIndex) )->pszID);
		c_lbCommand.SetItemData(iLbIndex, (DWORD)(*itIndex) );

		itIndex++, iLbIndex++;
	}

	return iLbIndex;
}

// ADVANCE namespace declared in "AdvanceCommand.h"
void CMGCommandPage::AddAdvanceMenu()
{
	enum { BUF_SIZE = 100 };
	TCHAR sID[BUF_SIZE];
	::ZeroMemory(sID, BUF_SIZE * sizeof(TCHAR));

	for(int i = 0; i < ADVANCE::CommandCount; i++)
	{
		int nCopied = ::LoadString(CResourceInstance::Get(), ADVANCE::Commands[i].uID, sID, BUF_SIZE);
		if( nCopied )
			AddCommand((WORD)ADVANCE::Commands[i].dwValue, sID, ADVANCE::CAT_ADVANCE);
	}
}
